; ** por compatibilidad se omiten tildes **
; ==============================================================================
; TRABAJO PRACTICO 3 - System Programming - ORGANIZACION DE COMPUTADOR II - FCEN
; ==============================================================================
; definicion de rutinas de atencion de interrupciones

%include "imprimir.mac"

BITS 32

%define TAREA_QUANTUM		2
%define TABLERO_ADDR 		0x003C0000

pausa: db "Juego Pausado                      "
pausa_len: equ $ - pausa

reanudar: db "Juego Reanudado                                "
reanudar_len: equ $ - reanudar

max_pages_reached: db "Cantidad maxima de paginas alcanzada."
max_pages_reached_len: equ $ - max_pages_reached

extern sched_jugador_actual
extern sched_indice_actual
extern sched_proximo_indice
extern sched_remover_tarea
extern sched_idle

extern game_iniciar
extern game_terminar
extern game_duplicar
extern game_migrar
extern game_estaTerminado

extern mmu_handle_page_fault


;; PIC
extern fin_intr_pic1

;;
;; Definición de MACROS
;;

%macro ISR 3
global _isr%1

_isr%1_mensaje: db %2

_isr%1:
    call sched_jugador_actual
    mov ebx, eax
    push eax
    call sched_remover_tarea
    add esp, 4
    
    add ebx, 18
    imprimir_texto_mp _isr%1_mensaje, %3, 0x07, ebx, 11
    
    call sched_idle
    call sched_jmp
    
    iret
    jmp $
%endmacro




;;
;; Rutina de atención de las EXCEPCIONES

ISR 0, 'Divide Error', 12
ISR 1, 'RESERVED', 8
ISR 2, 'NMI Interrupt', 13
ISR 3, 'Breakpoint', 10
ISR 4, 'Overflow', 8
ISR 5, 'BOUND Range Exceeded', 20
ISR 6, 'Invalid Opcode (Undefined Opcode)', 33
ISR 7, 'Device Not Available', 20
ISR 8, 'Double Fault', 12
ISR 9, 'Coprocessor Segment Overrun', 27
ISR 10, 'Invalid TSS', 11
ISR 11, 'Segment Not Present', 19
ISR 12, 'Stack-Segment Fault', 19
ISR 13, 'General Protection', 18
ISR 15, 'Reserved', 8
ISR 16, 'x87 FPU Error', 13
ISR 17, 'Alignment Check', 15
ISR 18, 'Machine Check', 13
ISR 19, 'SIMD FP Exception', 17



;;
;; Datos
;;
; Scheduler
reloj_numero:		 	dd 0x00000000
reloj:  				db '|/-\'

tick_counter: dd 0

offset : dd 0
selector: dw 0


pausado: dw 0
; pausado: 0 corriendo
; pausado: 1 por pausar
; pausado: 2 ya pausado


;;
;; Rutina de atención de las EXCEPCIONES
;;
global _isr14
;;
;; Rutina de atención de Page Fault
;;
_isr14:
	cli
	
	pushad			; guardo los registros GP
	mov edi, [esp + 0x20]	; cargo el error code en edi
	
	mov edx, 1		; edx = mascara para obtener bit P
	and edx, edi
	cmp edx, 0
	jne .protectionViolation

		xor eax, eax
		call sched_jugador_actual	
		mov ebx, eax				; ebx: jugador actual
		mov edx, cr2
		and edx, 0xFFFFFFF8			; edx: direccion virtual incial de la pagina
		push ebx
		push edx
		call mmu_handle_page_fault	; unsigned int mmu_handle_page_fault(address, task_id)
		add esp, 2*4

		cmp eax, 1		; mmu_handle_page_fault devuelve 1 si fue exitoso
		je .fin
		; si hubo error
		
		;imprimo el error en el estado de la tarea
		add ebx, 18
		imprimir_texto_mp max_pages_reached, max_pages_reached_len, 0x07, ebx, 11
		
		;remover tarea
		push ebx
		call sched_remover_tarea
		add esp, 1*4
	
		jmp .fin

	.protectionViolation:
		; que hacemos en este caso?
		
	.fin:
		mov dword [tick_counter], 0 ; reset tick counter
		call schedule

		popad		; reestablecemos los registros GP

		add esp, 4	; saco el error code
		sti
		iret
 	
 	
global _isr32
;;
;; Rutina de atención del RELOJ
;;
_isr32:
 	cli

 	pushad
 	pushfd

 	call proximo_reloj
    call fin_intr_pic1
 	
    mov ax, [pausado]
    
    ; si no esta pausado, intercambio tareas
    cmp ax, 0
	je .schedule
    
    ; si esta por pausar, debo activar la tarea idle
    cmp ax, 1
    je .idle
    
    ; si esta pausado, no intercambio tareas.
    cmp ax, 2
    je .no_jump
    
    .idle:
    ;xchg bx, bx
    mov word [pausado], 2
    call sched_idle
    call sched_jmp
    ;
    ;mov word [selector], 0x48
    ;jmp far [offset]
    jmp .no_jump
    
    .schedule:
    
    ;incremento el tick counter
	inc dword [tick_counter]
	
	; llegue al final de QUANTUM?
	cmp dword [tick_counter], TAREA_QUANTUM
	jb .no_jump

    call schedule
    
    .no_jump:
 	popfd
 	popad
 	sti
 	iret

schedule:
    mov dword [tick_counter], 0 ; reset tick counter
    call sched_indice_actual
    mov ebx, eax		    ; ebx indice actual
    call sched_proximo_indice
    cmp eax, ebx            ; si es la misma tarea, no hago el salto.
    je .fin

    call sched_jmp

 	.fin:
    ret


; salta a la tarea indicada en AX
sched_jmp:	
    shl ax, 3
    mov word [selector], ax
    
    ;tlbflush
    mov eax, cr3
    mov cr3, eax
    
    jmp far [offset]
    ret


; muestra el relojito abajo a la derecha de la pantalla
proximo_reloj:
	pushad

	inc DWORD [reloj_numero]
	mov ebx, [reloj_numero]
	cmp ebx, 0x4
	jl .ok
		mov DWORD [reloj_numero], 0x0
		mov ebx, 0
	.ok:
		add ebx, reloj
		imprimir_texto_mp ebx, 1, 0x0f, 24, 79
		
		call game_estaTerminado
		cmp eax, 1					; termino el juego?
		je .fin
			cmp word [pausado], 0   ; si esta corriendo la tarea
			jne .fin
			
			; se esta ejecutando una tarea
			call sched_jugador_actual
			add eax, 18
			imprimir_texto_mp ebx, 1, 0x0f, eax, 1

	.fin:
	popad
	ret


;;
;; Rutina de atención del TECLADO
;;
global _isr33

_isr33:
	cli
 	pushad
 	pushfd
	call fin_intr_pic1

	in al, 0x60
	cmp al, 0x19	; P
	jne no_es_p
        cmp word [pausado], 2   ; si ya esta pausado, no hago nada
        je fin33
        
        mov word [pausado], 1
    
		imprimir_texto_mp pausa, pausa_len, 0x0f, 24, 0
		jmp fin33
	
	no_es_p:
	cmp al, 0x13	; R
	jne fin33
        mov word [pausado], 0
		imprimir_texto_mp reanudar, reanudar_len, 0x0f, 24, 0
			
fin33:
 	popfd
 	popad
	sti
	iret

;;
;; Rutinas de atención de las SYSCALLS
;;


; duplicar
global _isr0x80

_isr0x80:
    cli
    
    ;eax: modo
    cmp eax, 111
    je .duplicar
    
    .migrar:
    ;ebx: fila_src
    ;ecx: columna_src
    ;edx: fila_dst
    ;esi: columna_dst
    call sched_jugador_actual ; eax: id jugador actual
        
    push esi
    push edx
    push ecx
    push ebx
    push eax
    call game_migrar
    
    ;game_migrar(int nro_jugador, int fil_src, int col_src, int fil_dst, int col_dst);
    add esp, 5*4
    
    jmp .fin
    
    .duplicar:
    ;ebx: fila
    ;ecx: columna
    call sched_jugador_actual ; eax: id jugador actual
    
    push ecx
    push ebx
    push eax
    call game_duplicar
    
    ;unsigned int game_duplicar(int nro_jugador, int fil, int col) 
    add esp, 3*4

    .fin:
    mov dword [tick_counter], 0 ; reset tick counter
    call schedule
    
    sti
    iret

global _isr0x90

_isr0x90:
    cli

    cmp eax, 300
    je .game_iniciar
    cmp eax, 200
    je .game_terminar
    jmp .fin
    
    .game_iniciar:
	call game_iniciar
	jmp .fin
	    
    .game_terminar:
	call game_terminar
    
    .fin:
    sti
    iret    
